/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */

package hirt;

import java.io.File;
import java.util.Vector;

/**
 *
 * @author adieffe
 */
public class Session
{
    protected int id;
    /** List of all scenarios avaiable to player */
    protected Vector<Scenario> scenarioList;
    /** The index of the scenario currently being played */
    protected int scenarioIndex;
    /** The actual scenario thats currently being played */
    protected Scenario currentScenario;
    /** The list of all the players in this session */
    protected Vector<Player> playerList;
    /** A list of all the chat messages that has gone on during this session */
    protected Vector<CommunicationAction> chatLog;
    /** A log of all the actions that have happened in this Session */
    protected Vector<Action> actionLog;
    //protected Vector<Item> itemList;
    /** The player that created this session */
    protected Player creator;
    
    //protected Player localPlayer;   // Player that is local to the program/computer.

    protected final static int STATE_INITIALIZE      = -1;  // Session initializing, no one can join yet.
    protected final static int STATE_WAITING         = 0;   // Session is waiting for player/choosing scenario/assigning roles.
    protected final static int STATE_PLAYING         = 1;   // Scenario is selected and loaded and being played.
    protected final static int STATE_REVIEW          = 2;   // Session is complete, players reviewing solution.
    protected final static int STATE_DESTROY         = 3;   // Session complete, being destroyed.
    protected final static int SUBSTATE_NULL         = 4;   // occurs when substate isn't need i.e. waiting
    protected final static int SUBSTATE_PLACECAR     = 5;   // occurs during PLAYING when a player is placing a car
    protected final static int SUBSTATE_PLACEITEM    = 6;   // occurs during PLAYING when a player is placing a item
    protected final static int SUBSTATE_OPTIMAL      = 7;   // occurs during REVIEW when a player is seeing the optimal solution
    protected final static int SUBSTATE_PREFORMED    = 8;   // occurs during REVIEW when a player is reviewing the preformed solution

    protected final static int MODE_PLAY    = 0;    // When the session is being played by responders
    protected final static int MODE_EDITOR  = 1;    // When the session is being edited by the administrator
    protected final static int MODE_REVIEW  = 2;    // When the session is just reviewing a scenario solution (non interactive).

    protected final static int DEFAULT_MODE = MODE_PLAY;
    protected int mode;
    protected int state;
    protected int subState;

    public Session( int id )
    {
        setId( id );

        state = STATE_INITIALIZE;
        subState = SUBSTATE_NULL;
        scenarioList = new Vector<Scenario>();
        scenarioIndex = -1; // This is the default value (we need to change it).
        this.setMode(DEFAULT_MODE);
        currentScenario = null;
        playerList = new Vector<Player>();
        //protected Vector<Action> chatLog; // TODO Add this functionality when Action is finished being coded.
        creator = null;
        chatLog = new Vector<CommunicationAction>();
        actionLog = new Vector<Action>();

        currentScenario = new Scenario();
    }

    public void setId( int id )
    {
        this.id = id;
    }

    public int getId()
    {
        return id;
    }

    public void setCreator(Player creator)
    {
        this.creator = creator;
    }

    public Player getCreator()
    {
        return creator;
    }

    public void setCurrentScenario(Scenario suggestedScenario) throws Exception
    {
        // Andrew2Zack: TODO Make a deep copy of the scenario passed.
        //Scenario copiedScenario = ( Scenario )suggestedScenario.clone();
        //currentScenario = copiedScenario;
        // INSTEAD OF THIS:
        currentScenario.itemList.clear();
        currentScenario = suggestedScenario;

        int tmp = getScenarioList().indexOf(suggestedScenario);
        if (tmp >= 0)
        {
            setScenarioIndex(tmp);
        }
        else
        {
            // We may need to deep copy this, for safety reasons.
            addScenario(currentScenario);
            setScenarioIndex(getScenarioList().size()-1);
        }
    }

    public Scenario getCurrentScenario()
    {
        return currentScenario;
    }

    /*
    public void setPlayerList(Vector<Player> playerList) throws Exception
    {
        if (playerList != null)
            this.playerList = playerList;
        else
            throw new Exception("Can't set null playerList");

    }
    */

    public Vector<Player> getPlayerList()
    {
        return playerList;
    }

    /*
    public Vector<Player> getPlayerList()
    {
        if( currentScenario == null )
        {
            return( playerList );
        }
        else
        {
            playerList.clear();

            Vector<Item> itemList = currentScenario.getItemList();

            if( itemList == null )
            {
                return( playerList );
            }
            else
            {
                System.out.println( "getPlayerList(): " );

                int index;
                for( index = 0; index < itemList.size(); index++ )
                {
                    Item tempItem = itemList.get( index );

                    if( tempItem instanceof Player )
                    {
                        System.out.println( tempItem.getId() );
                        playerList.add( ( Player )tempItem);
                    }
                }
            }

            return( playerList );
        }
    }
    */

    /*public void addPlayer(Player newPlayer)
    {
        newPlayer.setId(playerList.size());
        playerList.add(newPlayer);
    }

    public void removePlayer(Player player)
    {
        for (int i = player.getId()+1; i < playerList.size(); i++)
        {
            playerList.get(i).setId(i-1);
        }
        playerList.remove(player);
        player.setId(-1);
    }*/

    // TODO: Andrew2Zack: I think this should basically just call setCurrentScenario,
    // but maybe with precaution locks in place
    // (ie, don't let it change in the middle of gameplay such as status == STATE_PLAYING).
    public void setScenarioIndex(int scenarioIndex) throws Exception
    {
        if (scenarioIndex >=0 && scenarioIndex < scenarioList.size())
        {
            this.scenarioIndex = scenarioIndex;
            currentScenario=scenarioList.elementAt(scenarioIndex);
        }
        else if (scenarioIndex == -1)
        {
             this.scenarioIndex = scenarioIndex;
            currentScenario=null;
        }
        else
        {
            throw new Exception("Invalid Index (" + scenarioIndex + ")");
        }
        

        // NOTE This should probably change what scenario the session is playing.
        /*if( state == STATE_SCENARIO_ENDED )
        {
            if( ++scenarioIndex >= scenarioList.size() )
            {
                
            }
        }
        else
        {
            // TODO Throw exception here!
        }*/
    }

    public int getScenarioIndex()
    {
        return scenarioIndex;
    }

    public void setScenarioList(Vector<Scenario> scenarioList)
    {
        this.scenarioList = scenarioList;
    }

    public Vector<Scenario> getScenarioList()
    {
        return scenarioList;
    }

    public void addPlayer( Player newPlayer ) throws Exception
    {
        if (newPlayer != null)
        {
            Vector<Player> tempPlayerList = getPlayerList();

            // TODO Add exception for this.
            if( !tempPlayerList.contains( newPlayer ) )
            {
                if (currentScenario != null)
                    currentScenario.addItem(newPlayer);
                tempPlayerList.add( newPlayer );

            }
        }
        else
        {
            throw new Exception("Cannot add null players");
        }
    }

    public void removePlayer( Player specifiedPlayer ) throws Exception
    {
        Vector<Player> tempPlayerList = getPlayerList();
        if (tempPlayerList.contains(specifiedPlayer))
        {
            //currentScenario.removeItem(specifiedPlayer);
            tempPlayerList.remove(specifiedPlayer);
            if (tempPlayerList.size() == 0)
            {
                state = STATE_DESTROY;
            }
        }
        else
        {
            throw new Exception("Cannot remove player that isn't in the list");
        }
    }

    public void removeItem( Item item)
    {
        /*for (int i = 0; i < item.itemList.size(); i++)
        {
            removeItem(item.itemList.get(i));
            i--;
            if (item.itemList.size() == 0)
                break;
        }*/

        Item container = item.container;
        if (container != null)
            container.removeItem(item);

        Item owner = item.container;
        if (owner != null)
            owner.removeItem(item);



        //currentScenario.removeItem(item);

        if (item instanceof Automobile)
        {
            Player controller = getPlayerByRole(((Automobile)item).getRoleId());
            controller.removeCar(item);
        }
    }

    public void addScenario( Scenario newScenario ) throws Exception
    {
        Vector<Scenario> tempScenarioList = getScenarioList();
        if (newScenario == null)
            throw new Exception("Cannot add null scenarios");
        // TODO Add exception for this.
        if( !tempScenarioList.contains( newScenario ) )
        {
            tempScenarioList.add( newScenario );
            if (tempScenarioList.size() == 1)
            {
                setScenarioIndex(0);
            }
        }
    }

    // TODO fill in code for removeScenario()
    public void removeScenario( Scenario specifiedScenario ) throws Exception
    {
        Vector<Scenario> tempScenarioList = getScenarioList();
        if (specifiedScenario == null)
            throw new Exception("Cannot remove null scenarios");
        // TODO Add exception for this.
        if (tempScenarioList.size() == 0)
            throw new Exception("Cannot remove scenarios from empty scenario list");
        else if( tempScenarioList.contains( specifiedScenario ) )
        {
            tempScenarioList.remove( specifiedScenario );
            if (specifiedScenario == currentScenario)
            {
                if (tempScenarioList.size() > 0)
                    setScenarioIndex(0);
                else
                    setScenarioIndex(-1);
            }
        }
        else
            throw new Exception("Specified Scenario is not in the Scenario list");
    }

    /*public Player getLocalPlayer()
    {
        return localPlayer;
    }

    public void setLocalPlayer( Player localPlayer )
    {
        this.localPlayer = localPlayer;
    }*/

    public int getState()
    {
        return state;
    }

    public int nextState()
    {
        state++;
        state %= 3;
        subState = SUBSTATE_NULL;
        return state;
    }

    public int pauseGame()
    {
        state = STATE_WAITING;
        return state;
    }

    public int resumeGame()
    {
        state = STATE_PLAYING;
        return state;
    }

    /*public int getSubState()
    {
        return subState;
    }

    public int setSubState(int substate)
    {
        if (substate == SUBSTATE_NULL)
        {
            this.subState = substate;
            return subState;
        }
        else if((substate == SUBSTATE_PLACECAR || substate == SUBSTATE_PLACEITEM) && state == STATE_PLAYING )
        {
            this.subState = substate;
            return subState;
        }
        else if ((substate == SUBSTATE_OPTIMAL || substate == SUBSTATE_PREFORMED) && state == STATE_REVIEW )
        {
            this.subState = substate;
            return subState;
        }
        return -1;
    }*/

    public Vector<Item> getItemList()
    {
        if( currentScenario == null )
        {
            return( null );
        }
        else
        {
            return( currentScenario.getItemList() );
        }
    }

    public int getMode() {
        return mode;
    }

    public void setMode(int mode) {
        this.mode = mode;
    }

    /*public void setItemList( Vector<Item> itemList )
    {
        currentScenario.setItemList( itemList );
    }*/

    public Vector<CommunicationAction> getChatLog() {
        return chatLog;
    }

    public void setChatLog(Vector<CommunicationAction> chatLog) {
        this.chatLog = chatLog;
    }

    /**
     * Adds a chat message to the Chat Log
     * @param comunique
     */
    public void addChatMessage(CommunicationAction comunique)
    {
        chatLog.add(comunique);
    }

    /**
     * Assigns the passed car to the passed autmobile
     * @param automobile
     * @param player
     */
    public void assignAutomobileToPlayer( Automobile automobile, Player player )
    {
        if( ( player != null ) && ( automobile != null ) )
        {
            automobile.setOwner( player );
            player.addCar( automobile );
        }
    }

    /**
     * Add an action to the action log
     * @param action
     */
    public void addAction(Action action)
    {
        actionLog.add(action);
    }

    public Action getAction(int index)
    {
        return actionLog.get(index);
    }

    public int getActionLogLength()
    {
        return actionLog.size();
    }

    /**
     * This method goes through all the scenario save files found in the passed folder
     * Gets the name of every scenario and add it to the scenario list
     * @param folderName
     * @return
     */
    public boolean loadScenarioList(String folderName)
    {
        try
        {
            File directoryOfPdfs = new File(folderName);

            if (directoryOfPdfs.isDirectory())
            {
                String filenames[] = directoryOfPdfs.list(); //make array of filenames;

                String file;
                for (int i = 0; i < filenames.length; i++)
                {
                    file = filenames[i];
                    if (file.endsWith(".txt"))
                    {
                        Scenario loadable = new Scenario();
                        if (loadable.basicLoadFromFile(folderName + "/" + file));   // Forward slash is cross platform (makes it work on Mac and Linux).
                            this.scenarioList.add(loadable);
                    }
                }
            }
        }
        catch (Exception ex)
        {
                return false;
        }

        return true;
    }

    /**
     * Returns the player that is playing the passed role
     * if no player plays that role, it returns null
     * @param roleId
     * @return
     */
    public Player getPlayerByRole( int roleId )
        {
            int index;
            Vector<Player> playerList = getPlayerList();

            // Go through each player in the list of players.
            for( index = 0; index < playerList.size(); index++ )
            {
                Player tempPlayer = playerList.get( index );

                Vector<Role> roleList = tempPlayer.getRoles();

                // Go through each role that player is assigned to.
                int roleIndex;
                for( roleIndex = 0; roleIndex < roleList.size(); roleIndex++ )
                {
                    Role tempRole = roleList.get( roleIndex );

                    // Check each role to see if it matches the desired role id.
                    if( tempRole.getId() == roleId )
                    {
                        // Finally found a player that plays this role.
                        return( tempPlayer );
                    }
                }
            }

            // No player plays this role!
            return( null );
        }

    /**
     * Returns a boolean based on whether the passsed scenario is in the scenarioList
     * @param scenario
     * @return
     */
    public boolean containsScenario(Scenario scenario)
    {
        String name = scenario.getName();
        for (int i = 0; i < scenarioList.size(); i++)
        {
            if (scenarioList.get(i).getName().equals(name))
                return true;
        }
        return false;
    }
    
    // TODO: Code addItem and removeItem function.
}
